package oceanlife.pathfinding;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.awt.Graphics;
import java.awt.Polygon;

import oceanlife.db;

public class Obstacles {
	
    private TriangleArrayList<Triangle> obstacles = new TriangleArrayList<Triangle>();// Obstacles defined as triangles

	private ArrayList<Triangulation> metaObs = new ArrayList<Triangulation>();
	
	private ArrayList<Pnt[]> inputObstacles = new ArrayList<Pnt[]>();
	public void setInputObstacle(Pnt[] pnts){
		inputObstacles.add(pnts);
	}

    public ArrayList<Pnt[]> getInputObstacles() {
		return inputObstacles;
	}
    
    public ArrayList<SimpleObstacle> getSimpleObstacles(){
    	ArrayList<SimpleObstacle> simpleObs = new ArrayList<SimpleObstacle>();
    	for(Pnt[] inputOb : inputObstacles){
    		ArrayList<Pnt> obPoints = new ArrayList<Pnt>();
    		for(Pnt pnt : inputOb){
        		obPoints.add(pnt);
    		}
    		try {
				simpleObs.add(new SimpleObstacle(obPoints));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	return simpleObs;
    }
    
    public void clear(){
        obstacles = new TriangleArrayList<Triangle>();
        metaObs = new ArrayList<Triangulation>();
    	inputObstacles = new ArrayList<Pnt[]>();
    }

	public void readObsParams(ArrayList<Pillar> pillars, Double xOffset, Double yOffset, Double pillarSpacing) {
		for(int i = 0; i < pillars.size(); i++){
			inputObstacles.add(pillars.get(i).getPnts(xOffset+(pillarSpacing*i), yOffset));
		}
		//add corridor walls
		Double wallExtraLength = 50.0;
		Double wallThickness = 20.0;
		inputObstacles.add(new Pnt[]{new Pnt(xOffset-wallExtraLength,yOffset),
									 new Pnt(xOffset+(pillars.size()*pillarSpacing)+wallExtraLength,yOffset),
									 new Pnt(xOffset+(pillars.size()*pillarSpacing)+wallExtraLength,yOffset-wallThickness),
									 new Pnt(xOffset-wallExtraLength,yOffset-wallThickness)});
		inputObstacles.add(new Pnt[]{new Pnt(xOffset-wallExtraLength,yOffset+Pillar.maxPosition+wallThickness),
									 new Pnt(xOffset+(pillars.size()*pillarSpacing)+wallExtraLength,yOffset+Pillar.maxPosition+wallThickness),
									 new Pnt(xOffset+(pillars.size()*pillarSpacing)+wallExtraLength,yOffset+Pillar.maxPosition),
									 new Pnt(xOffset-wallExtraLength,yOffset+Pillar.maxPosition)});
        Triangulation obsTriangleGen = new Triangulation(DelaunayTriangleTranslator.initialTriangle);

        for(Pnt[] inputObstacle : inputObstacles){
	        
	        obsTriangleGen = new Triangulation(DelaunayTriangleTranslator.initialTriangle);
	        for(Pnt inputPnt : inputObstacle){
	        	obsTriangleGen.delaunayPlace(inputPnt);
	        }
	        obstacles.addAll(DelaunayTriangleTranslator.extractTriangles(obsTriangleGen));
	       	metaObs.add(obsTriangleGen);
        }

	}

	public void readObs(String obstacleSet) {
		/*System.out.println("obstacle set: "+obstacleSet);
		//if(obstacleSet.equals("1")){
		    ResultSet obstacleSetResult = db.exec("SELECT obstacle_id FROM `ocean_life`.`obstacle_set` WHERE obstacle_set_id="+obstacleSet+";");
		    try {
				while(obstacleSetResult.next()){
					ArrayList<Pnt> pntArray = new ArrayList<Pnt>();
					ResultSet obstacleResult = db.exec("SELECT obstacle_point_id FROM `ocean_life`.`obstacle` WHERE obstacle_id="+obstacleSetResult.getString(1)+";");
					while(obstacleResult.next()){
						ResultSet obstaclePointResult = db.exec("SELECT x,y FROM `ocean_life`.`obstacle_point` WHERE obstacle_point_id="+obstacleResult.getString(1)+";");
						while(obstaclePointResult.next()){
							Pnt newPnt = new Pnt(obstaclePointResult.getDouble(1),obstaclePointResult.getDouble(2));
							pntArray.add(newPnt);
						}
					}
					if(pntArray.size()>0){
						inputObstacles.add(pntArray.toArray(new Pnt[0]));
					}
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
        
        Triangulation obsTriangleGen = new Triangulation(DelaunayTriangleTranslator.initialTriangle);

        for(Pnt[] inputObstacle : inputObstacles){
	        
	        obsTriangleGen = new Triangulation(DelaunayTriangleTranslator.initialTriangle);
	        for(Pnt inputPnt : inputObstacle){
	        	obsTriangleGen.delaunayPlace(inputPnt);
	        }
	        obstacles.addAll(DelaunayTriangleTranslator.extractTriangles(obsTriangleGen));
	       	metaObs.add(obsTriangleGen);
        }*/

	}

    
	public Obstacles(){
    }
    
    public int metaObstacleCount(){
    	return metaObs.size();
    }
    
    public int getObstacleCount(){
    	return inputObstacles.size();
    }
    
    public Triangulation getMetaObstacle(int index){
    	return metaObs.get(index);
    }
    
    public int getPolygonCount(){
    	return inputObstacles.size();
    }
    
    public Polygon getPolygon(int index){
    	Pnt[] polygonPoints = inputObstacles.get(index);
    	int polygonSize = polygonPoints.length;
    	int[] xpoints = new int[polygonSize];
    	int[] ypoints = new int[polygonSize];
    	for(int i = 0; i < polygonSize;i++){
    		xpoints[i] = (int) Math.round(polygonPoints[i].coord(0));
    		ypoints[i] = (int) Math.round(polygonPoints[i].coord(1));
    	}
    	return new Polygon(xpoints, ypoints, polygonSize);
    }
    
    public TriangleArrayList<Triangle> getObstacles() {
		return obstacles;
	}

	public Triangulation findMetaOb(Triangle faulty) {
		for(Triangulation trian : metaObs){
			for(Triangle tri : trian){
				if(tri.equals(faulty)){
					return trian;
				}
			}
		}
		return null;
	}
	
	
	
	public Triangle get(int i) {
		return obstacles.get(i);
	}
	public int getIndex(Triangle tri) {
		return obstacles.getIndex(tri);
	}
	public void remove(int index) {
		obstacles.remove(index);
		
	}
	public void addAll(ArrayList<Triangle> newTriangles) {
		obstacles.addAll(newTriangles);	
	}
	public int size() {
		return obstacles.size();
	}
	
	//index = input obstacle index
	public Pnt getClosestPoint(int index, Pnt pos) {
		Pnt[] pg = inputObstacles.get(index);
		Pnt closestPoint = pg[0];
		Double closestPointDistance = pos.distanceTo(closestPoint);
		for(int i = 0; i < pg.length;i++){
			int j = i+1;
			if(j == pg.length){
				j = 0;
			}
			Line2 polyLine = new Line2(pg[i],pg[j]);
			Pnt potClosestPoint = polyLine.closestPoint(pos);
			double potClosestPointDistance = pos.distanceTo(potClosestPoint);
			if(potClosestPointDistance < closestPointDistance){
				closestPoint = potClosestPoint;
				closestPointDistance = potClosestPointDistance;
			}
		}
		return closestPoint;
	}

	public Line2 getClosestLine(int index, Line2 line) {
		Pnt[] pg = inputObstacles.get(index);
		Pnt[] ln = line.getPnts();
		
		Pnt pgPnt = pg[0];
		Pnt lnPnt = ln[0];
		Double closestDistance = pgPnt.distanceTo(lnPnt);

		for(int k = 0; k < ln.length;k++){
			for(int i = 0; i < pg.length;i++){
				int j = i+1;
				if(j == pg.length){
					j = 0;
				}
				Line2 polyLine = new Line2(pg[i],pg[j]);
				Pnt potClosestPoint = polyLine.closestPoint(ln[k]);
				double potClosestDistance = ln[k].distanceTo(potClosestPoint);
				if(potClosestDistance < closestDistance){
					pgPnt = potClosestPoint;
					lnPnt = ln[k];
					closestDistance = potClosestDistance;
				}
			}
		}		
		for(int i = 0; i < pg.length;i++){
			Pnt potClosestPoint = line.closestPoint(pg[i]);
			double potClosestPointDistance = pg[i].distanceTo(potClosestPoint);
			if(potClosestPointDistance < closestDistance){
				lnPnt = potClosestPoint;
				pgPnt = pg[i];
				closestDistance = potClosestPointDistance;
			}
		}
		return new Line2(lnPnt,pgPnt);
	}

	public static void main(String[] arg){
		Obstacles obs = new Obstacles();
		Pnt testpnt = new Pnt(15.0,5.0);
		obs.setInputObstacle(new Pnt[]{new Pnt(0.0,0.0),new Pnt(10.0,0.0),new Pnt(10.0,10.0),new Pnt(0.0,10.0)});
		System.out.println(testpnt);
		Pnt closest = obs.getClosestPoint(0, testpnt);
		System.out.println(closest);
	}

}
